/**
 * \file  observer.h
 * \brief Definition of Observer template.
 *
 * ASO: Antiviral Sequence Optimizer
 * <http://aso.googlecode.com/>
 * Copyright (C) 2010 Velez Ezequiel, Peralta Andres, FuDePAN
 *
 * This file is part of the ASO project.
 *
 * Contents:       Header file for ASO providing template Observer.
 *
 * System:         ASO
 * Language:       C++
 *
 * Author:         Velez Ezequiel, Peralta Andres
 * E-Mail:
 *
 * ASO is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * ASO is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with ASO.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#ifndef OBSERVER_H
#define OBSERVER_H

#include <mili/mili.h>

/*! Observer propietario: es dueño del objeto*/
template < class T, class R = void >
struct Observer
{
    virtual R update(const T* t) = 0;
    virtual ~Observer() {};
};

/*! Grupo de observers */
template<class T>
class ObserversGroupObserver: public Observer<T, void>
{
private:
    typedef std::list<Observer<T, void>*> ObserverGroup;
    typedef mili::CAutonomousIterator<ObserverGroup> ObsGroupIterator;

    ObserverGroup observers;     //! grupo de observadores de terapias

public:
    ObserversGroupObserver(): observers()
    {}

    //! Metodoss para interactuar con los observers
    inline void update(const T* newObject);
    inline void attach(Observer<T, void>* obs);
    inline void detach(Observer<T, void>* obs) throw(mili::ElementNotFound);
};

template<class T>
inline void ObserversGroupObserver<T>::update(const T* newObject)
{
    ObsGroupIterator it(observers);
    while (!it.end())
    {
        (*it)->update(newObject);
        ++it;
    }
}

template<class T>
inline void ObserversGroupObserver<T>::attach(Observer<T, void>* obs)
{
    mili::insert_into(observers, obs);
}

template<class T>
inline void ObserversGroupObserver<T>::detach(Observer<T, void>* obs) throw(mili::ElementNotFound)
{
    const bool SUCCESS = remove_first_from(observers, obs);
    if (!SUCCESS)
        throw mili::ElementNotFound();
}

#endif
